﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OthelloGame
{
    public class OthelloGameBoard
    {
        #region Game Board Basic Members
        PieceColors playersTurn;
        OthelloBoardGamePiece[,] gameBoard = new OthelloBoardGamePiece[8, 8];
        #endregion
        #region other private members
        private int whiteCount;
        private int blackCount;
        //private int smartWhiteCount;
        //private int smartBlackCount;
        #endregion

        #region Constructor
        public OthelloGameBoard()
        {
            
            playersTurn = PieceColors.Black;
            gameBoard[3,3] = new OthelloBoardGamePiece(PieceColors.White);
            gameBoard[3,4] = new OthelloBoardGamePiece(PieceColors.Black);
            gameBoard[4,3] = new OthelloBoardGamePiece(PieceColors.Black);
            gameBoard[4,4] = new OthelloBoardGamePiece(PieceColors.White);
        }
        public OthelloGameBoard(OthelloGameBoard BoardToClone)
        {
            
            playersTurn = BoardToClone.playersTurn;
            for (int a = 0; a < 8; a++)
            {
                for (int b = 0; b < 8; b++)
                {
                    gameBoard[a,b] = BoardToClone.gameBoard[a,b];
                }
            }
        }
        #endregion

        public OthelloBoardGamePiece this[int i, int j]
        {
            get
            {
                if (i < 0 || j < 0 || i >= 8 || j >= 8) throw new IndexOutOfRangeException();
                return gameBoard[i, j];
            }
        }

        #region Available Options background work
         private List<OthelloBoardLocation> getAvailableOptionLocations()
        {
            List<OthelloBoardLocation> newAvailableOptionLocations = new List<OthelloBoardLocation>();
            for (int hindex = 0; hindex < 8; hindex++)
            {
                for (int vindex = 0; vindex < 8; vindex++)
                {
                    if (gameBoard[hindex,vindex] == null)
                    {
                        OthelloBoardLocation newLocation = new OthelloBoardLocation(hindex, vindex);
                        if (isLocationAnOption(newLocation))
                        {
                            newAvailableOptionLocations.Add(newLocation);
                        }
                    }
                }
            }
            return newAvailableOptionLocations;
        }       
        #region ExamineGameBoardForOption

        private bool isLocationAnOption(OthelloBoardLocation locationToCheck)
        {
            bool isOption = false;
            //if the current players piece is there.
            if (gameBoard[locationToCheck.HorizontalPlace,locationToCheck.VerticalPlace] == null)
            {
                //Check Eight Directions
                if (diagonalUpLeftIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (upIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (diagonalUpRightIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (leftIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (rightIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (diagonalDownLeftIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (downIsAnOption(locationToCheck))
                {
                    isOption = true;
                }
                else if (diagonalDownRightIsAnOption(locationToCheck))
                {
                    isOption = true;
                }

            }
            return isOption;
        }
        private bool diagonalUpLeftIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace - 1;
            int vindex = locationToCheck.VerticalPlace - 1;
            while (hindex >= 0 && vindex >= 0)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex--;
                vindex--;
            }
            return false;
        }
        private bool upIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int vindex = locationToCheck.VerticalPlace - 1;
            while (vindex >= 0)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[locationToCheck.HorizontalPlace,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                vindex--;
            }
            return false;
        }
        private bool diagonalUpRightIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace + 1;
            int vindex = locationToCheck.VerticalPlace - 1;
            while (hindex < 8 && vindex >= 0)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex++;
                vindex--;
            }
            return false;
        }
        private bool leftIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace - 1;
            while (hindex >= 0)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,locationToCheck.VerticalPlace];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex--;
            }
            return false;
        }
        private bool rightIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace + 1;
            while (hindex < 8)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,locationToCheck.VerticalPlace];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex++;
            }
            return false;
        }
        private bool diagonalDownLeftIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace - 1;
            int vindex = locationToCheck.VerticalPlace + 1;
            while (hindex >= 0 && vindex < 8)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex--;
                vindex++;
            }
            return false;
        }
        private bool downIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int vindex = locationToCheck.VerticalPlace + 1;
            while (vindex < 8)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[locationToCheck.HorizontalPlace,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                vindex++;
            }
            return false;

        }
        private bool diagonalDownRightIsAnOption(OthelloBoardLocation locationToCheck)
        {
            bool wasOpposite = false;
            int hindex = locationToCheck.HorizontalPlace + 1;
            int vindex = locationToCheck.VerticalPlace + 1;
            while (hindex < 8 && vindex < 8)
            {
                OthelloBoardGamePiece examinationPiece = this.gameBoard[hindex,vindex];
                if (examinationPiece == null)
                {
                    return false;
                }
                else
                {
                    //if the piece color is the same as the players turn, ie black piece blacks turn.
                    if (examinationPiece.PieceColor == playersTurn)
                    {
                        if (!wasOpposite)
                        {
                            return false;
                        }
                        else
                        {
                            return true;
                        }
                    }
                    else
                    {
                        if (!wasOpposite)
                        {
                            wasOpposite = true;
                        }
                    }
                }
                hindex++;
                vindex++;
            }
            return false;
        }

        #endregion
      
        #endregion

        #region See The Board
        public Boolean GameOver()
        {
            Boolean gameOver = false;
            if (AvailableOptionLocations.Count == 0)
            {
                OthelloGameBoard testBoard = new OthelloGameBoard(this);
                testBoard.changePlayersTurn();
                if (AvailableOptionLocations.Count == 0)
                {
                    gameOver = true;
                }
            }
            return gameOver;
        }
   
        #region Counting Pits
        public int WhiteCount
        {
            get{
                if(whiteCount == 0){
                    getCounts();
                }
                return whiteCount;
            }
        }
        public int BlackCount
        {
            get
            {
                if (blackCount == 0)
                {
                    getCounts();
                }
                return blackCount;
            }
        }
        // Smart counts
        //public int SmartWhiteCount
        //{
        //    get
        //    {
        //        if (smartWhiteCount == 0)
        //        {
        //            getSmartCount();
        //        }
        //        return smartWhiteCount;
        //    }
        //}

        //public int SmartBlackCount
        //{
        //    get
        //    {
        //        if (smartBlackCount == 0)
        //        {
        //            getSmartCount();
        //        }
        //        return SmartBlackCount;
        //    }
        //}

        public int PitCount(PieceColors colorToGetCounted)
        {
            if (colorToGetCounted == PieceColors.Black)
            {
                return BlackCount;
            }
            else
            {
                return WhiteCount;
            }
        }

        // Smart pit count
        //public int SmartPitCount(PieceColors colorToGetCounted)
        //{
        //    if (colorToGetCounted == PieceColors.Black)
        //    {
        //        return SmartBlackCount;
        //    }
        //    else
        //    {
        //        return SmartWhiteCount;
        //    }
        //}

        private void getCounts()
        {
            OthelloBoardGamePiece foundPit;
            for (int indexa = 0; indexa < 8; indexa++)
            {
                for (int indexb = 0; indexb < 8; indexb++)
                {
                    foundPit = gameBoard[indexa, indexb];
                    if (foundPit != null)
                    {
                        if (foundPit.IsBlack)
                        {
                            blackCount++;
                        }
                        else
                        {
                            whiteCount++;
                        }
                    }
                }
            }
        }

        //private void getSmartCount()
        //{
        //    OthelloBoardGamePiece foundPit;
        //    int location_utility = 0;

        //    for (int i = 0; i < 8; i++)
        //    {
        //        for (int j = 0; j < 8; j++)
        //        {
        //            foundPit = gameBoard[i, j];
        //            if (foundPit != null)
        //            {
        //                // 50
        //                if ((i % 7 == 0) && (j % 7 == 0))
        //                {
        //                    location_utility = 50;
        //                }
        //                // -1
        //                if ((Math.Abs(i - j) == 1) && ((i + j == 1) || (i + j==13)))
        //                {
        //                    location_utility = -1;
        //                }
        //                if ((Math.Abs(i - j) == 6) && ((i + j == 6) || (i + j == 8)))
        //                {
        //                    location_utility = -1;
        //                }
        //                // 5
        //                if ((Math.Abs(i - j) == 2) && ((i + j == 2) || (i + j == 12)))
        //                {
        //                    location_utility = 5;
        //                }
        //                if ((Math.Abs(i - j) == 5) && ((i + j == 5) || (i + j == 9)))
        //                {
        //                    location_utility = 5;
        //                }
        //                // -10
        //                if ((Math.Abs(i - j) == 0) && ((i + j == 2) || (i + j == 12)))
        //                {
        //                    location_utility = -10;
        //                }
        //                if ((Math.Abs(i - j) == 5) && (i + j == 7))
        //                {
        //                    location_utility = -10;
        //                }
        //                // 2
        //                if ((Math.Abs(i - j) == 3) && ((i + j == 3) || (i + j == 11)))
        //                {
        //                    location_utility = 2;
        //                }
        //                if ((Math.Abs(i - j) == 4) && ((i + j == 4) || (i + j == 10)))
        //                {
        //                    location_utility = 2;
        //                }
        //                // 1
        //                if ((i >= 1 && i <= 6) && (j >= 1 && j <= 6))
        //                {
        //                    if ((Math.Abs(i - j) == 0) && ((i + j == 2) || (i + j == 12)))
        //                    { }
        //                    else if ((Math.Abs(i - j) == 5) && (i + j == 7))
        //                    { }
        //                    else if ((Math.Abs(i - j) == 0) && ((i + j == 6) || (i + j == 8)))
        //                    {
        //                        location_utility = 0;
        //                    }
        //                    else if ((Math.Abs(i - j) == 1) && (i + j == 7))
        //                    {
        //                        location_utility = 0;
        //                    }
        //                    else
        //                    {
        //                        location_utility = 1;
        //                    }
        //                }

        //                if (foundPit.IsBlack)
        //                {
        //                    smartBlackCount += location_utility;
        //                }
        //                else
        //                {
        //                    smartWhiteCount += location_utility;
        //                }
        //            }
        //        }
        //    }
        //}

        #endregion

        public PieceColors PlayersTurn
        {
            get
            {
                return this.playersTurn;
            }
        }
        public Boolean IsLegalMove(OthelloBoardLocation placeToCheck)
        {
            if (AvailableOptionLocations.Contains(placeToCheck))
            {
                return true;
            }
            return false;
        }
        public List<OthelloBoardLocation> AvailableOptionLocations
        {
            get
            {
                return getAvailableOptionLocations();
            }
        }
 
        ///Might return null if there is no piece at that location.
        public OthelloBoardGamePiece ExamineBoard(OthelloBoardLocation placeToLook)
        {
            return gameBoard[placeToLook.HorizontalPlace, placeToLook.VerticalPlace];
        }
        #endregion

        #region ChangeBoard in some way
        private void changePlayersTurn()
        {
            if (playersTurn == PieceColors.Black)
            {
                playersTurn = PieceColors.White;
            }
            else
            {
                playersTurn = PieceColors.Black;
            }
        }

        #region change pits
        private void resetMembers()
        {
            this.whiteCount = 0;
            this.blackCount = 0;
        }

        private void changeAdjacentPits(OthelloBoardLocation newPitLocation)
        {
                
            //Change if nine possible directions.
            if (gameBoard[newPitLocation.HorizontalPlace, newPitLocation.VerticalPlace] == null)
            {
                //Check Eight Directions
                if (diagonalUpLeftIsAnOption(newPitLocation))
                {
                    changeDiagonalUpLeft(newPitLocation);
                }
                if (upIsAnOption(newPitLocation))
                {
                    changeUp(newPitLocation);
                }
                if (diagonalUpRightIsAnOption(newPitLocation))
                {
                    changeDiagonalUpRight(newPitLocation);
                }
                if (leftIsAnOption(newPitLocation))
                {
                    changeLeft(newPitLocation);
                }
                if (rightIsAnOption(newPitLocation))
                {
                    changeRight(newPitLocation);
                }
                if (diagonalDownLeftIsAnOption(newPitLocation))
                {
                    changeDiagonalDownLeft(newPitLocation);
                }
                if (downIsAnOption(newPitLocation))
                {
                    changeDown(newPitLocation);
                }
                if (diagonalDownRightIsAnOption(newPitLocation))
                {
                    changeDiagonalDownRight(newPitLocation);
                }

            }
            gameBoard[newPitLocation.HorizontalPlace, newPitLocation.VerticalPlace] = new OthelloBoardGamePiece(playersTurn);
           
        }
        private bool changeDiagonalUpLeft(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace - 1;
            int vindex = locationToCheck.VerticalPlace - 1;
            while (hindex >= 0 && vindex >= 0 && gameBoard[hindex, vindex].PieceColor != playersTurn)
            {

                gameBoard[hindex, vindex] = new OthelloBoardGamePiece(playersTurn);
                hindex--;
                vindex--;
            }
            return false;
        }
        private bool changeUp(OthelloBoardLocation locationToCheck)
        {
            int vindex = locationToCheck.VerticalPlace - 1;
            while (vindex >= 0 && gameBoard[locationToCheck.HorizontalPlace, vindex].PieceColor != playersTurn)
            {

                gameBoard[locationToCheck.HorizontalPlace, vindex] = new OthelloBoardGamePiece(playersTurn);
                vindex--;
            }
            return false;
        }
        private bool changeDiagonalUpRight(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace + 1;
            int vindex = locationToCheck.VerticalPlace - 1;
            while (hindex < 8 && vindex >= 0 && gameBoard[hindex, vindex].PieceColor != playersTurn)
            {

                gameBoard[hindex, vindex] = new OthelloBoardGamePiece(playersTurn);
                hindex++;
                vindex--;
            }
            return false;
        }
        private bool changeLeft(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace - 1;
            while (hindex >= 0 && gameBoard[hindex, locationToCheck.VerticalPlace].PieceColor != playersTurn)
            {

                gameBoard[hindex, locationToCheck.VerticalPlace] = new OthelloBoardGamePiece(playersTurn);
                hindex--;
            }
            return false;
        }
        private bool changeRight(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace + 1;
            while (hindex < 8 && gameBoard[hindex, locationToCheck.VerticalPlace].PieceColor != playersTurn)
            {

                gameBoard[hindex, locationToCheck.VerticalPlace] = new OthelloBoardGamePiece(playersTurn);
                hindex++;
            }
            return false;
        }
        private bool changeDiagonalDownLeft(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace - 1;
            int vindex = locationToCheck.VerticalPlace + 1;
            while (hindex >= 0 && vindex < 8 && gameBoard[hindex, vindex].PieceColor != playersTurn)
            {

                gameBoard[hindex, vindex] = new OthelloBoardGamePiece(playersTurn);
                hindex--;
                vindex++;
            }
            return false;
        }
        private bool changeDown(OthelloBoardLocation locationToCheck)
        {
            int vindex = locationToCheck.VerticalPlace + 1;
            while (vindex < 8 && gameBoard[locationToCheck.HorizontalPlace, vindex].PieceColor != playersTurn)
            {

                gameBoard[locationToCheck.HorizontalPlace, vindex] = new OthelloBoardGamePiece(playersTurn);
                vindex++;
            }
            return false;

        }
        private bool changeDiagonalDownRight(OthelloBoardLocation locationToCheck)
        {
            int hindex = locationToCheck.HorizontalPlace + 1;
            int vindex = locationToCheck.VerticalPlace + 1;
            while (hindex < 8 && vindex < 8 && gameBoard[hindex, vindex].PieceColor != playersTurn)
            {

                gameBoard[hindex, vindex] = new OthelloBoardGamePiece(playersTurn);
                hindex++;
                vindex++;
            }
            return false;
        }
        #endregion

        public void PlacePit(OthelloBoardLocation newPitLocation)
        {

            if (AvailableOptionLocations.Contains(newPitLocation))
            {
                changeAdjacentPits(newPitLocation);
                changePlayersTurn();
                // because this resets settings by not coppying them.
                resetMembers();
                if (AvailableOptionLocations.Count == 0)
                {
                    changePlayersTurn();
                }
            }
        }
        #endregion


        #region equals
        // override object.Equals
        public override bool Equals(object obj)
        {
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }
            OthelloGameBoard other = (OthelloGameBoard) obj;
            if (other.PlayersTurn != PlayersTurn) return false;
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    OthelloBoardGamePiece a = other.gameBoard[i, j];
                    OthelloBoardGamePiece b = gameBoard[i, j];
                    if (a == null || b == null)
                    {
                        if (a != b) return false;
                    }
                    else
                    {
                        if (!a.Equals(b)) return false;
                    }
                }
            }

            return true;
        }

        // override object.GetHashCode
        public override int GetHashCode()
        {
            int hash = 1;
            int prime = 31;
            OthelloBoardGamePiece pieces;
            hash = hash * prime + this.PlayersTurn.GetHashCode();
            for (int a = 0; a < 8; a++)
            {
                for (int b = 0; b < 8; b++)
                {
                    pieces = this.gameBoard[a, b];
                    hash = hash * prime + ((pieces == null) ? 0 : pieces.GetHashCode());
                }
            }
            return hash;
        }
        #endregion
   
    }
}
